﻿using PageAdmin.Utils.ORM;
using PageAdmin.Utils.ORM.PropertyDescriptor;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace PageAdmin.Utils.BLL
{
    /// <summary>
    /// 根据id或删除通用BLL
    /// </summary>
    public class DeleteBLL<T> : IDelete<T> where T : class, new()
    {
        /// <summary>
        /// 执行前的委托
        /// </summary>
        public Func<T, TipsInfo> Executing { get; set; }

        /// <summary>
        /// 执行后的委托
        /// </summary>
        public Func<T, TipsInfo> Executed { get; set; }

        /// <summary>
        /// 限制条件
        /// </summary>
        string conditionLimit { get; set; }

        /// <summary>
        /// 数据库对象
        /// </summary>
        private DataBaseContext _DbContext;

        private TipsInfo _TipsInfo;

        public DeleteBLL(DataBaseContext dataBaseContext)
        {
            _TipsInfo = new TipsInfo();
            _DbContext = dataBaseContext;
        }


        /// <summary>
        /// 根据id删除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public TipsInfo Delete(int id)
        {
            T deleteModel = null;
            TipsInfo tipsInfo = new TipsInfo();
            //如果定义了执行前和执行后的委托，那么查询出删除的模型作为委托参数
            deleteModel = _DbContext.DbSet<T>().Find(id);
            if (deleteModel == null)
            {
                tipsInfo.State = 0;
                tipsInfo.Msg = "无效的ID";
                return tipsInfo;
            }
            try
            {
                string table = _DbContext.DbSet<T>().TableName;
                if (Executing != null)
                {
                    tipsInfo = Executing.Invoke(deleteModel);
                }
                if (tipsInfo.State == 1)
                {
                    if (deleteModel is MultipleLevelModelBase<T>) //如果是多级分类表
                    {
                        tipsInfo = deleteChild(table, id);
                    }
                    _DbContext.DbSet<T>().Delete(id);
                }
                if (Executed != null)
                {
                    tipsInfo = Executed.Invoke(deleteModel);
                }
                if (tipsInfo.State == 1)
                {
                    //删除附属表记录
                    tipsInfo = DeleteSubtableData(id);
                }
                if (tipsInfo.State == 1)
                {
                    //删除附件记录
                    tipsInfo = deleteAttachment(table, id);
                }
            }
            catch (Exception e)
            {
                tipsInfo.State = 0;
                tipsInfo.Msg = e.Message;
            }
            return tipsInfo;
        }

        /// <summary>
        /// 根据条件参数
        /// </summary>
        /// <param name="condition"></param>
        /// <param name="paramter"></param>
        /// <returns></returns>
        public TipsInfo Delete(string condition, object paramter)
        {
            string table = _DbContext.DbSet<T>().TableName;
            _DbContext.SetDbParamter(paramter);
            foreach (dynamic itemData in _DbContext.Query(table, "[Id]", condition))
            {
                int id = itemData.Id;
                _TipsInfo = Delete(id);
                if (_TipsInfo.State == 0)
                {
                    return _TipsInfo;
                }
            }
            return _TipsInfo;
        }

        /// <summary>
        /// 同步删除附属表,循环删除
        /// </summary>
        /// <returns></returns>
        private TipsInfo DeleteSubtableData(int parentId)
        {
            IEnumerable<ModelFieldMapped> subdataMappedList = _DbContext.DbSet<T>().ModelFieldMappingList.Where(c => c.IsSubDataMapped == true);
            if (subdataMappedList.Count() == 0)
            {
                return _TipsInfo;
            }

            //反射创建泛型实例，每个附属表创建一个DleleBLL实例
            Type deleteType = typeof(DeleteBLL<>); //泛型Dll
            foreach (ModelFieldMapped modelFieldMapped in subdataMappedList)
            {
                if(!modelFieldMapped.SubdataMappedDescriptor.SyncDelete){
                    continue;
                }
                Type[] templateTypeSet = new[] { modelFieldMapped.PropertyType}; //泛型参数类型
                Type genericType = deleteType.MakeGenericType(templateTypeSet);//创建泛型的Delete泛型类
                MethodInfo deleteMethod = genericType.GetMethod("Delete", new Type[] { typeof(int) });
                var obj = Activator.CreateInstance(genericType, new object[] { _DbContext });//根据类型创建Delete实例,带数据库对象带进进去。
                foreach (dynamic itemData in _DbContext.Query(modelFieldMapped.SubdataMappedDescriptor.SubtableName, "Id", $"{modelFieldMapped.SubdataMappedDescriptor.ForeignKey}={parentId}"))
                {
                    int id = itemData.Id;
                    _TipsInfo = (TipsInfo)deleteMethod.Invoke(obj, new object[] { id });
                    if (_TipsInfo.State == 0)
                    {
                        return _TipsInfo;
                    }
                }
            }
            return _TipsInfo;
        }


        /// <summary>
        /// 同步删除附件记录
        /// </summary>
        /// <returns></returns>
        private TipsInfo deleteAttachment(string parentTable, int parentId)
        {
            IEnumerable<ModelFieldMapped> modelFieldMappedList = _DbContext.DbSet<T>().ModelFieldMappingList.Where(c => c.IsAttachmentMapped);
            if (modelFieldMappedList.Count() == 0)
            {
                return _TipsInfo;
            }
            return AttachmentDataBLL.DeleteAttachment(parentTable, parentId);
        }

        /// <summary>
        /// 多级表的子级删除
        /// </summary>
        /// <param name="guid"></param>
        /// <param name="delRelativeTable"></param>
        private TipsInfo deleteChild(string table, int parentId)
        {
            if (parentId == 0) { return _TipsInfo; }
            IEnumerable<dynamic> childList = _DbContext.Query(table, "[Id]", "parentId = " + parentId);
            if (childList == null) { return _TipsInfo; }
            foreach (dynamic item in childList)
            {
                int id = item.Id;
                _TipsInfo = deleteChild(table, id);
                if (_TipsInfo.State == 0) { return _TipsInfo; }
                _TipsInfo = Delete(id); //不能多线程下使用，事务导致排它锁，事务未提交时排它锁一直存在
                if (_TipsInfo.State == 0) { return _TipsInfo; }
            }
            return _TipsInfo;
        }
    }
}